﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Configuration;
using System.Reflection;
using PServiceBus.Core.Runtime;
using PServiceBus.Core.Runtime.Configuration;
using System.Xml;
using System.IO;
using PServiceBus.Core.Interface;

namespace PServiceBus.ComponentContainer {
	public partial class Service : ServiceBase {
		private int _batchSize;
		private int _interval;
		private string _componentTypeName;
		private string _componentAsmName;

		private Type _componentType = null;
		public Service() {
			InitializeComponent();
			System.IO.Directory.SetCurrentDirectory(System.AppDomain.CurrentDomain.BaseDirectory);
			ServiceName = ConfigurationProvider.ComponentConfig.Name;
		}

		private void Setup() {
			_batchSize = ConfigurationProvider.ComponentContainerConfig.BatchSize;
			_interval = ConfigurationProvider.ComponentContainerConfig.Interval;
			_componentTypeName = ConfigurationProvider.ComponentConfig.Type;
			_componentAsmName = ConfigurationProvider.ComponentConfig.Assembly;
			PServiceBus.Core.Runtime.SerializationBootstrapper.Configure();
			PServiceBus.EmailTransport.SerializationBootstrapper.Configure();
			PServiceBus.MSSQLTransport.SerializationBootstrapper.Configure();
			PServiceBus.WCF.NetTcpTransport.SerializationBootstrapper.Configure();
			PServiceBus.Transports.SerializationBootstrapper.Configure();
		}

		protected override void OnStart(string[] args) {
			Setup();
			var asm = Assembly.Load(new AssemblyName(_componentAsmName));
			_componentType = (asm.GetType(_componentTypeName));
			PServiceBus.Core.Runtime.ComponentServices.ComponentServiceProcessor.StartNew(_componentType, _interval, _batchSize);
		}

		protected override void OnStop() {
			PServiceBus.Core.Runtime.ComponentServices.ComponentServiceProcessor.ShutDown(_componentType);
		}

		protected override void OnShutdown() {
			PServiceBus.Core.Runtime.ComponentServices.ComponentServiceProcessor.SaveState(_componentType);
			base.OnShutdown();
		}

		private static void LoadConfig(string serviceName) {

			var elements = ConfigurationParser.Process("configurations.xml")
					.First(x => (x["config"] as Dictionary<string, object>)["name"].ToString() == serviceName)
					.ToDictionary(kv => kv.Key, kv => (kv.Value as Dictionary<string, object>)
						.ToDictionary(kvl => kvl.Key, kvl => kvl.Value == null ? string.Empty : kvl.Value.ToString()));



			foreach (var node in elements) {
				if (node.Key == "componentConfig") {
					var componentConfig = ReflectionHelper.New<IComponentConfig>(c =>
					{
						c.Assembly = node.Value["assembly"];
						c.Name = node.Value["name"];
						c.Type = node.Value["type"];
					});
					ConfigurationProvider.ComponentConfig = componentConfig;
				} else if (node.Key == "componentContainerConfig") {
					var componentContainerConfig = ReflectionHelper.New<IComponentContainerConfig>(c =>
					{
						c.Address = node.Value["address"];
						c.AddressID = node.Value["addressID"];
						c.BatchSize = Convert.ToInt32(node.Value["batchSize"]);
						c.Interval = Convert.ToInt32(node.Value["interval"]);
					});
					ConfigurationProvider.ComponentContainerConfig = componentContainerConfig;
				} else if (node.Key == "loggerConfig") {
					var loggerConfig = ReflectionHelper.New<ILoggerConfig>(l =>
					{
						l.Type = node.Value["type"];
						l.ErrorLogPath = node.Value["errorLogPath"];
						l.LogPath = node.Value["logPath"];
						l.TracePath = node.Value["tracePath"];
						l.Enabled = Convert.ToBoolean(node.Value["enabled"]);
					});
					ConfigurationProvider.LoggerConfig = loggerConfig;
				}
			}
		}

		static void Main(string[] args) {
			if (args.Length > 0) LoadConfig(args[0]);
			ServiceBase[] ServicesToRun;
			ServicesToRun = new ServiceBase[] 
			{ 
				new Service() 
			};
			ServiceBase.Run(ServicesToRun);
		}
	}
}
